package com.ruoyi.common.utils;

import com.ruoyi.common.Result;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;


public class AESUtil {
    private static final String CHARSET_NAME="utf-8";
    private static final String DECRYPT_FAIL="解密失败";
    private static final String ENCRYPT_FAIL="加密失败";
    private static final String ALGORITHM="AES";
    private static final String TRANSFORMATION="AES/ECB/PKCS5Padding";
    private static final byte[] PLUS_BYTE_16={ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
    private static final byte[] PLUS_BYTE_32 ={ 0x08, 0x08, 0x04, 0x0b, 0x02, 0x0f, 0x0b, 0x0c,0x01, 0x03, 0x09, 0x07, 0x0c, 0x03, 0x07, 0x0a, 0x04, 0x0f,0x06, 0x0f, 0x0e, 0x09, 0x05, 0x01, 0x0a, 0x0a, 0x01, 0x09,0x06, 0x07, 0x09, 0x0d };
    private static final Integer BYTE_LEN=16;
    private static final Boolean IS_BASE64=true;//true 是base64 ，false 是hex
    private static byte [] getPlusByte(Integer byteLen){
        switch (byteLen){
            case 32:
                return PLUS_BYTE_32;
            default:
                return PLUS_BYTE_16;
        }
    }
    //解决java.security.NoSuchAlgorithmException: Cannot find any provider supporting AES/CBC/PKCS7Padding
    static {
        Security.addProvider(new BouncyCastleProvider());
    }
    /**
     * 加密
     * @return 加密后的字符串
     */
    public static Result Encrypt(String src, String key)  {
        // 判断密钥是否为空
        if(StringUtils.isEmpty(key)){
            return Result.FAIL("the key is null or empty");
        }
        try {
            // 密钥补位
            int plus= BYTE_LEN-key.length();
            byte[] data = key.getBytes(CHARSET_NAME);
            byte[] raw = new byte[BYTE_LEN];
            byte[] plusbyte=getPlusByte(BYTE_LEN);

            for(int i=0;i<BYTE_LEN;i++)
            {
                if (data.length > i)
                    raw[i] = data[i];
                else
                    raw[i] = plusbyte[plus];
            }

            SecretKeySpec skeySpec = new SecretKeySpec(raw, ALGORITHM);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);	// 算法/模式/补码方式
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
            byte[] encrypted = cipher.doFinal(src.getBytes(CHARSET_NAME));

            if(IS_BASE64) {
                String base64Str = Base64Utils.encodeToString(encrypted);
                if (StringUtils.isEmpty(base64Str)) {
                    return Result.FAIL(ENCRYPT_FAIL);
                }
                return Result.SUCCESS(base64Str);
            }else {
                String hexStr = Hex.toHexString(encrypted);
                if (StringUtils.isEmpty(hexStr)) {
                    return Result.FAIL(ENCRYPT_FAIL);
                }
                return Result.SUCCESS(hexStr.toUpperCase());
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
     return Result.FAIL(ENCRYPT_FAIL);
    }

    /**
     * 解密
     * @param  src 解密字符串
     * @param  key 密钥
     * @return 解密后的字符串
     */
    public static Result Decrypt(String src, String key) throws Exception {
        try {
            // 判断Key是否正确
            // 判断密钥是否为空
            if(StringUtils.isEmpty(key)){
                return Result.FAIL("the key is null or empty");
            }
            // 密钥补位
            int plus= BYTE_LEN-key.length();
            byte[] data = key.getBytes(CHARSET_NAME);
            byte[] raw = new byte[BYTE_LEN];
            byte[] plusbyte=getPlusByte(BYTE_LEN);
            for(int i=0;i<BYTE_LEN;i++)
            {
                if (data.length > i)
                    raw[i] = data[i];
                else
                    raw[i] = plusbyte[plus];
            }

            SecretKeySpec skeySpec = new SecretKeySpec(raw, ALGORITHM);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);

            //byte[] encrypted1 = new Base64().decode(src);//base64
            byte[] encrypted1 =null;

            if(IS_BASE64){
                encrypted1=Base64Utils.decodeFromString(src);
            }else {
             encrypted1=toByteArray(src);//十六进制
            }


            try {
                byte[] original = cipher.doFinal(encrypted1);
                String originalString = new String(original,CHARSET_NAME);
                if(StringUtils.isEmpty(originalString)){
                    return Result.FAIL(DECRYPT_FAIL);
                }
                return Result.SUCCESS(originalString);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return Result.FAIL(DECRYPT_FAIL);
    }

    /**
     * 将byte[]转为各种进制的字符串
     * @param bytes byte[]
     * @param radix 可以转换进制的范围，从Character.MIN_RADIX到Character.MAX_RADIX，超出范围后变为10进制
     * @return 转换后的字符串
     */
    public static String binary(byte[] bytes, int radix){
        return new BigInteger(1, bytes).toString(radix);	// 这里的1代表正数
    }

    /**
     * 16进制的字符串表示转成字节数组
     *
     * @param hexString 16进制格式的字符串
     * @return 转换后的字节数组
     **/
    public static byte[] toByteArray(String hexString) {
        if (hexString.isEmpty())
            throw new IllegalArgumentException("this hexString must not be empty");

        hexString = hexString.toLowerCase();
        final byte[] byteArray = new byte[hexString.length() / 2];
        int k = 0;
        for (int i = 0; i < byteArray.length; i++) {//因为是16进制，最多只会占用4位，转换成字节需要两个16进制的字符，高位在先
            byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
            byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
            byteArray[i] = (byte) (high << 4 | low);
            k += 2;
        }
        return byteArray;
    }
    /**
     * 解密
     *
     * @param content 目标密文
     * @param key     秘钥
     * @param iv      偏移量
     * @return
     */
    public static String decrypt(String content,String key, String iv) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            byte[] sessionKey = java.util.Base64.getDecoder().decode(key);
            SecretKeySpec keySpec = new SecretKeySpec(sessionKey, ALGORITHM);
            byte[] ivByte = java.util.Base64.getDecoder().decode(iv);
            AlgorithmParameterSpec paramSpec = new IvParameterSpec(ivByte);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, paramSpec);
            return new String(cipher.doFinal(Base64.decodeBase64(content)), CHARSET_NAME);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
//    public static void main(String[] args) throws Exception {
//
//        // System.out.println(DateUtil.getCurrentTime().getTime());
////        // 密钥
//       String key = "54dfd5ae34bc4861a0da031811430533";
////        // 需要加密的字符串
//        String src = "zsrCLFJbPgeATIKp";
////
////        System.out.println(src);
////
////        // 加密
//        Result enString = Encrypt(src, key);
//        System.out.println("加密后的字串是：" + enString.getData().toString());
//
////        // 解密
////        Result DeString = Decrypt(enString.getData().toString(), key);
////        System.out.println("解密后的字串是：" + DeString.getData().toString());
//
//       // String ak= "54dfd5ae34bc4861a0da031811430533";//.substring(8, 24);
//        Result dd=  Decrypt(enString.getData().toString(),key);
//        System.out.println(dd.getData());
//
//    }

}
